﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Opennav.MapGenerator.Geometry
{
    public class Area
    {
        public Area()
        {
            Reset();
        }

        private Area(int minLongitude, int minLatitude, int maxLongitude, int maxLatitude)
        {
            this.MinLongitude = minLongitude;
            this.MinLatitude = minLatitude;
            this.MaxLongitude = maxLongitude;
            this.MaxLatitude = maxLatitude;
        }

        public int MinLongitude { get; set; }

        public int MinLatitude { get; set; }

        public int MaxLongitude { get; set; }

        public int MaxLatitude { get; set; }

        public int Width { get { return MaxLongitude - MinLongitude; } }

        public int Height { get { return MaxLatitude - MinLatitude; } }

        public int MaxDimension { get { return Math.Min(Width, Height); } }

        public int MinDimension { get { return Math.Max(Width, Height); } }

        public Coordinate Center
        {
            get
            {
                return new Coordinate((MaxLongitude + MinLongitude) / 2, (MaxLatitude + MinLatitude) / 2);
            }
        }

        public void Reset()
        {
            this.MinLongitude = int.MaxValue;
            this.MaxLatitude = int.MinValue;
            this.MinLatitude = int.MaxValue;
            this.MaxLongitude = int.MinValue;
        }

        public void AddToBounds(Coordinate coordinate)
        {
            if (coordinate.Longitude > MaxLongitude) MaxLongitude = coordinate.Longitude;
            if (coordinate.Longitude < MinLongitude) MinLongitude = coordinate.Longitude;
            if (coordinate.Latitude > MaxLatitude) MaxLatitude = coordinate.Latitude;
            if (coordinate.Latitude < MinLatitude) MinLatitude = coordinate.Latitude;
        }

        public void AddRangeToBounds(IEnumerable<Coordinate> coordinates)
        {
            foreach (Coordinate c in coordinates)
                AddToBounds(c);
        }

        public void AddToBounds(Area area)
        {
            if (area.MinLongitude < MinLongitude) MinLongitude = area.MinLongitude;
            if (area.MaxLongitude > MaxLongitude) MaxLongitude = area.MaxLongitude;
            if (area.MinLatitude < MinLatitude) MinLatitude = area.MinLatitude;
            if (area.MaxLatitude > MaxLatitude) MaxLatitude = area.MaxLatitude;
        }

        public Area[] SplitBounds(int nx, int ny)
        {
            Area[] areas = new Area[nx * ny];
            int area = 0;
            int dx = (this.MaxLongitude - this.MinLongitude) / nx;
            int dy = (this.MaxLatitude - this.MinLatitude) / ny;
            if ((this.MaxLongitude - this.MinLongitude) % nx > 0)
                dx++;
            if ((this.MaxLatitude - this.MinLatitude) % ny > 0)
                dy++;
            for (int y = 0; y < ny; y++)
            {
                for (int x = 0; x < nx; x++)
                {
                    areas[area++] = new Area(this.MinLongitude + x * dx, this.MinLatitude + y * dy, x == nx - 1 ? this.MaxLongitude : this.MinLongitude + (x + 1) * dx, y == ny - 1 ? this.MaxLatitude : this.MinLatitude + (y + 1) * dy);
                }
            }
            return areas;
        }

        public bool Contains(Coordinate c)
        {
            if (c.Longitude >= MinLongitude && c.Longitude <= MaxLongitude && c.Latitude >= MinLatitude && c.Latitude <= MaxLatitude)
                return true;
            else
                return false;
        }
    }
}
